import axios from 'axios'
import { Message } from 'element-ui'
import { getTimeStamp } from '@/utils/auth'

// 引入路由
import router from '@/router'
// 设定过期时间
const TimeOutDuration = 2000
// 引入vuex
import store from '@/store'
// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})

// 请求拦截器
// 在每个请求 headers 带上 token（如果请求本身没有带，但是数据中有token）
service.interceptors.request.use(config => {
  // 如果请求本身没有带上token但是vuex里面存在，就应该默认注入
  if (!config.headers.Authorization && store.getters.token) {
    // 在注入之前，先判断一下是否已经过期
    if (!isTimeOut()) {
      // 这里是JWT鉴权标准的Bearer Token 规范
      // 格式是： 'Bearer xxxxxx'
      config.headers.Authorization = `Bearer ${store.getters.token}`
    } else {
      // 这里是已经过期的状况
      // 登出操作删除数据
      store.dispatch('user/logout')
      // 跳回登录页面
      router.push('/login?redirect=' + location.hash.substring(1))
      // return Promise.reject 停止请求
      return Promise.reject(new Error('登录已经过期'))
    }
  }
  return config
}, err => {
  // 防御性编程，处理可能出现的报错
  Message.error(err.message)
  return Promise.reject(new Error(err.message))
})

// 响应拦截器
service.interceptors.response.use(
  // 网络层成功响应
  res => {
    // 结构响应数据
    const { message, data, success } = res.data
    console.log(success)
    // 数据层响应成功
    // 如果有成功数据则返回data
    if (success) {
      // 直接返回数据
      return data
    } else {
      // 数据层响应失败
      // 失败以后弹出提示然后停止这个请求
      Message.error(message)
      // 不能直接返回数据, 因为请求会以为成功
      // 需要返回一个拒绝的 Promise 走 catch 流程
      return Promise.reject(new Error(message))
    }
  },
  // 网络层失败响应
  err => {
    // 处理失败逻辑
    // 这里是网络层面的失败，以前都是用来处理断网，写错url之类的
    // 现在多了一种可能性，就是token失效
    // 这里就应该做判断，如果是code===10002
    if (err.response && err.response.data && err.response.data.code === 10002) {
      // 退出
      // 做登出和跳转操作
      store.dispatch('user/logout')
      router.push('/login?redirect=' + location.hash.substring(1))
    } else {
      // 其他处理
      console.dir(err)
      // 失败以后弹出提示
      Message.error(err.message)
    }

    return Promise.reject(new Error(err.message))
  }
)

// 验证token是否过期
function isTimeOut() {
  const currentTime = Date.now()
  const timeStamp = getTimeStamp()
  return (currentTime - timeStamp) / 1000 > TimeOutDuration
}
// 暴露
export default service
